﻿namespace YunQue.Core.WebExtension.Middlewares
{
    /// <summary>
    /// 接口权限中间件
    /// </summary>
    public class APIPermissionMiddleware
    {
        private readonly RequestDelegate _next;
        private static ConcurrentDictionary<string, APIPermissionAttribute> urlPermissionCodeDic = new ConcurrentDictionary<string, APIPermissionAttribute>();
        private static ConcurrentDictionary<string, bool> urlAllowAnonymousDic = new ConcurrentDictionary<string, bool>();
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="next"></param>
        public APIPermissionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        /// <summary>
        /// invoke
        /// </summary>
        /// <param name="context"></param>
        /// <param name="userContext"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext context, UserContext userContext)
        {
            //检测是否需要验证身份信息
            var url = context.Request.Path.ToString();
            bool isAllowAnonymous = urlAllowAnonymousDic.GetOrAdd(url, (key) =>
            {
                return context.GetEndpoint()?.Metadata?.GetMetadata<AllowAnonymousAttribute>() != null;
            });
            if (!isAllowAnonymous)
            {
                var apipermission = urlPermissionCodeDic.GetOrAdd(url, (key) =>
                {
                    return context.GetEndpoint()?.Metadata?.GetMetadata<APIPermissionAttribute>();
                });
                if (apipermission != null)
                {
                    var permission = await RedisWrapper.SMembersAsync<string>(userContext.Token + AppSettingManager.CACHEKEY_TENANTPERMISSION).ConfigureAwait(false);
                    if (permission == null) throw new Exception("无权限访问该接口");
                    var hasPermission = false;
                    switch (apipermission.OpreationType)
                    {
                        case OpreationType.And:
                            hasPermission = permission.All(p => apipermission.PermissionCodes.Contains(p));
                            break;
                        case OpreationType.Or:
                            hasPermission = permission.Any(p => apipermission.PermissionCodes.Contains(p));
                            break;
                    }
                    if (!hasPermission) throw new Exception("无权限访问该接口");
                }
            }
            await _next(context);
        }
    }
}
